home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * Routines to prepare objects according to view file matrix: *
- * *
- * Written by: Gershon Elber Ver 1.0, Jan. 1989 *
- *****************************************************************************/
-
- #include <math.h>
- #include <stdio.h>
- #include "program.h"
- #include "genmat.h"
-
- /* #define DEBUG1 Print edge/hash table content. */
-
- #define SAME_VERTEX(V1, V2) (APX_EQ(V1 -> Coord[0], V2 -> Coord[0]) && \
- APX_EQ(V1 -> Coord[1], V2 -> Coord[1]) && \
- APX_EQ(V1 -> Coord[2], V2 -> Coord[2]))
-
- #ifdef DEBUG1
- static void PrintEdgeContent(EdgeStruct *PEdge);
- static void DrawEdgeHashTable(void);
- static void DrawEdge(EdgeStruct *PEdge);
- #endif /* DEBUG1 */
-
- static int MinYLevel, MaxYLevel, CrntYLevel, PrintYLevel;
-
- static void PrepareOneObject(IPObjectStruct *PObject);
- static int PrepareOnePolygon(IPPolygonStruct *PPolygon, int IsPolygon);
- static void UpdateBBoxPolygon(IPPolygonStruct *PPolygon);
- static int UpdateEqnPolygon(IPPolygonStruct *PPolygon, int *ReversePoly);
- static void GenEdgesFromPoly(IPPolygonStruct *PPolygon, int IsPolygon);
- static void InsertEdgeToHashTbl1(EdgeStruct *PEdge);
- static void IntersectAllEdges(void);
- static void InsertEdgeToHashTbl2(EdgeStruct *PEdge);
- static int IntersectEdgeList(EdgeStruct *PEdge,
- EdgeStruct *PEList,
- int TestYMin);
- static int IntersectEdgeEdge(EdgeStruct *PEdge1,
- EdgeStruct *PEdge2,
- EdgeStruct **PEdgeNew1,
- EdgeStruct **PEdgeNew2);
- static void PrintPolyContent(IPPolygonStruct *PPoly);
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to prepare the given object for hidden surface analysis. M
- * If NumOfObjects == 0 then all the objects defined by the data sturcture M
- * are drawn. M
- * If GlblNumEdge != 0 then only GlblNumEdge first edges of each polygons M
- * are tested for visibility (usefull in case in input polygons has known M
- * repetition edges sequence which is redundent). M
- * *
- * PARAMETERS: M
- * PObjects: To prepare for hidden surface analysis. M
- * *
- * RETURN VALUE: M
- * void M
- * *
- * KEYWORDS: M
- * PrepareViewData M
- *****************************************************************************/
- void PrepareViewData(IPObjectStruct *PObjects)
- {
- int i;
-
- IritCPUTime(TRUE);
-
- for (i = 0; i < EDGE_HASH_TABLE_SIZE; i++)
- EdgeHashTable[i] = NULL;
- for (i = 0; i < POLY_HASH_TABLE_SIZE; i++)
- PolyHashTable[i] = NULL;
-
- if (!GlblQuiet)
- fprintf(stderr, "\nPass 2, Edges = ");
-
- while (PObjects) {
- if (IP_IS_POLY_OBJ(PObjects))
- PrepareOneObject(PObjects);
- PObjects = PObjects -> Pnext;
- }
-
- if (!GlblQuiet)
- fprintf(stderr, ", %6.2f seconds.", IritCPUTime(FALSE));
-
- IntersectAllEdges(); /* Break edges to visibily uniform sub-edges. */
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to prepare one object PObject for hidden surface analysis. *
- * *
- * PARAMETERS: *
- * PObject: Object to prepare for freeform analysis. *
- * *
- * RETURN VALUE: *
- * void *
- *****************************************************************************/
- static void PrepareOneObject(IPObjectStruct *PObject)
- {
- int Level;
- IPPolygonStruct *Ptemp,
- *PList = PObject -> U.Pl;
-
- while (PList) {
- Ptemp = PList -> Pnext;
-
- if (!IritPrsrIsConvexPolygon(PList)) {
- static int Printed = FALSE;
-
- if (!Printed) {
- fprintf(stderr,
- "\nWARNING: Non convex polygon(s) might be in data (see CONVEX in IRIT),\n\t\t\t\toutput can be wrong as the result!\n ");
- Printed = TRUE;
- }
- }
-
- if (PrepareOnePolygon(PList, IP_IS_POLYGON_OBJ(PObject))) {
- /* And add polygon into polygon hash table sorted by Ymin: */
- Level = (int) ((PList -> BBox[0][1] + 1.0) * POLY_HASH_TABLE_SIZE2);
- Level = BOUND(Level, 0, POLY_HASH_TABLE_SIZE1); /* Be 100% safe. */
- PList -> Pnext = PolyHashTable[Level];
- PolyHashTable[Level] = PList; /* Concat it to poly hash table. */
- }
-
- PList = Ptemp;
- }
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to prepare one poly PPolygon. *
- * Returns TRUE iff this object is a valid POLYGON (not a POLYLINE!). *
- * *
- * PARAMETERS: *
- * PPolygon: Poly to prepare for hideden surface analysis. *
- * IsPolygon: TRUE if polygon, FALSE otherwise (polyline etc.). *
- * *
- * RETURN VALUE: *
- * int: TRUE if successful, FALSE otherwise. *
- *****************************************************************************/
- static int PrepareOnePolygon(IPPolygonStruct *PPolygon, int IsPolygon)
- {
- int i, Reverse;
- RealType CpCoord[3];
- IPVertexStruct
- *PList = PPolygon -> PVertex;
-
- /* Make a circluar polygon list inlt a linear list by breaking the end. */
- while (PList != NULL && PList -> Pnext != PPolygon -> PVertex)
- PList = PList -> Pnext;
- if (PList)
- PList -> Pnext = NULL;
- PList = PPolygon -> PVertex;
-
- while (PList) {
- /* Convert the coordinate to screen space (in RealType pres.). */
- MatMultVecby4by4(CpCoord, PList -> Coord, GlblViewMat);
- for (i = 0; i < 3; i++)
- PList -> Coord[i] = CpCoord[i];
-
- PList = PList -> Pnext;
- }
- if (IsPolygon) {
- /* Find plane equation of poly, and let know if need to reverse. */
- if (!UpdateEqnPolygon(PPolygon, &Reverse))
- return FALSE;
- UpdateBBoxPolygon(PPolygon);/* Find X, Y extrem in screen space. */
- GenEdgesFromPoly(PPolygon, TRUE); /* Generate all its edges. */
- if (Reverse)
- IritPrsrReverseVrtxList(PPolygon);
- return TRUE;
- }
- else {
- GenEdgesFromPoly(PPolygon, FALSE); /* Generate all its edges. */
- return FALSE;
- }
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to update polygon boundary box in screen space. *
- * *
- * PARAMETERS: *
- * PPolygon: To update bounding box for, in palce. *
- * *
- * RETURN VALUE: *
- * void *
- *****************************************************************************/
- static void UpdateBBoxPolygon(IPPolygonStruct *PPolygon)
- {
- RealType *Coord, Xmin, Xmax, Ymin, Ymax; /* Bounding box of the polygon. */
- IPVertexStruct
- *PList = PPolygon -> PVertex;
-
- Xmin = Xmax = PList -> Coord[0];
- Ymin = Ymax = PList -> Coord[1];
- PList = PList -> Pnext;
- while (PList) {
- Coord = PList -> Coord;
- if (Coord[0] > Xmax)
- Xmax = Coord[0];
- if (Coord[0] < Xmin)
- Xmin = Coord[0];
- if (Coord[1] > Ymax)
- Ymax = Coord[1];
- if (Coord[1] < Ymin)
- Ymin = Coord[1];
- PList = PList -> Pnext;
- }
- PPolygon -> BBox[0][0] = Xmin;
- PPolygon -> BBox[1][0] = Xmax;
- PPolygon -> BBox[0][1] = Ymin;
- PPolygon -> BBox[1][1] = Ymax;
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to update plane equation of the given polygon. *
- * It is assumed that at least 3 points in polygon exists. The tuple that *
- * has the largest vector length is selected maximum accuracy. *
- * We IGNORE PLANE if was in data file. *
- * In addition, a test is made if all vertices are ordered such that the *
- * cross product of each 3 consecutive vertices (projected onto Z=0 plane) *
- * is allways positive. The polygon must be convex, so result might be either *
- * all positive or all negative. *
- * In the later case the order of the plane equation is reversed. *
- * *
- * PARAMETERS: *
- * PPolygon: Polygon to update plane for, and possibly reverse. *
- * ReversedPoly: TRUE if plane equation was reversed. *
- * *
- * RETURN VALUE: *
- * int: TRUE if successful, FALSE otherwise. *
- *****************************************************************************/
- static int UpdateEqnPolygon(IPPolygonStruct *PPolygon, int *ReversedPoly)
- {
- static int
- PolygonCount = 0;
- int i;
- RealType V1[3], V2[3], *Coord, *CoordNext, *CoordNextNext,
- Plane[3], Len, MaxPlane[3],
- MaxLen = 0.0;
- IPVertexStruct
- *PList = PPolygon -> PVertex;
-
- PolygonCount++;
-
- *ReversedPoly = FALSE;
-
- do { /* Search for 3 consequtive non-colinear point from polygon: */
- Coord = PList -> Coord;
- CoordNext = PList -> Pnext -> Coord;
- CoordNextNext = PList -> Pnext -> Pnext -> Coord;
- for (i = 0; i < 3; i++) { /* Prepare two vectors on polygon plane. */
- V1[i] = Coord[i] - CoordNext[i];
- V2[i] = CoordNext[i] - CoordNextNext[i];
- }
-
- /* Find plane normal by a cross product of the two vectors on plane: */
- Plane[0] = V1[1] * V2[2] - V1[2] * V2[1];
- Plane[1] = V1[2] * V2[0] - V1[0] * V2[2];
- Plane[2] = V1[0] * V2[1] - V1[1] * V2[0];
-
- /* Find vector Len. - we are looking for the biggest: */
- Len = sqrt(SQR(Plane[0]) + SQR(Plane[1]) + SQR(Plane[2]));
- if (Len > MaxLen) {
- for (i = 0; i < 3; i++)
- MaxPlane[i] = Plane[i];
- MaxLen = Len;
- }
- PList = PList -> Pnext; /* Try next tuple. */
- } while (PList -> Pnext -> Pnext != NULL);
-
- if (ABS(MaxLen) < SQR(EPSILON)) { /* Fail to find 3 non-colinear points. */
- if (GlblMore) {
- fprintf(stderr,
- "\nError: Invalid polygon (%d) found in file (zero edge length/colinear vertices):\n",
- PolygonCount);
- PrintPolyContent(PPolygon);
- }
- return FALSE;
- }
-
- for (i = 0; i < 3; i++)
- PPolygon -> Plane[i] = MaxPlane[i] / MaxLen;
-
- /* Make sure the Z component of the plane is positive: */
- if (PPolygon -> Plane[2] < 0.0) {
- for (i = 0; i < 3; i++)
- PPolygon -> Plane[i] = (-PPolygon -> Plane[i]);
- *ReversedPoly = TRUE;
- }
- else
- if (GlblBackFacing)
- return FALSE;
-
- PPolygon -> Plane[3] =
- (- Coord[0] * PPolygon -> Plane[0]
- - Coord[1] * PPolygon -> Plane[1]
- - Coord[2] * PPolygon -> Plane[2]);
-
- return TRUE;
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to generate all the edges from the given polygon in screen space. *
- * Edges are inserted to an edge hash table of EDGE_HASH_TABLE_SIZE *
- * entries. *
- * If global variable GlblNumEdge != 0 then only the first PGlblNumEdge *
- * edges are generated. *
- * If edge is INTERNAL it is marked as so. *
- * If this is polyline, the last edge is NOT generated. *
- * *
- * PARAMETERS: *
- * PPolygon: To generateedge from. *
- * IsPolygon: TRUE for polygon, FALSE otherwise (polyline etc.). *
- * *
- * RETURN VALUE: *
- * void *
- *****************************************************************************/
- static void GenEdgesFromPoly(IPPolygonStruct *PPolygon, int IsPolygon)
- {
- int CountEdges = GlblNumEdge;
- EdgeStruct *PEdge;
- IPVertexStruct
- *PList = PPolygon -> PVertex;
-
- if (!PList || !PList -> Pnext)
- return; /* If less than 2 vertices. */
-
- while (PList -> Pnext) {
- PEdge = (EdgeStruct *) IritMalloc(sizeof(EdgeStruct));
- PEdge -> Vertex[0] = PList;
- PEdge -> Vertex[1] = PList -> Pnext;
- PEdge -> Internal = IP_IS_INTERNAL_VRTX(PList);
- PEdge -> Pnext = NULL;
- InsertEdgeToHashTbl1(PEdge);
-
- if (!--CountEdges)
- return;
-
- PList = PList -> Pnext;
- }
- /* Close the contour to first vertex in list (if not polyline): */
- if (IsPolygon) {
- PEdge = (EdgeStruct *) IritMalloc(sizeof(EdgeStruct));
- PEdge -> Vertex[0] = PList;
- PEdge -> Vertex[1] = PPolygon -> PVertex;
- PEdge -> Internal = IP_IS_INTERNAL_VRTX(PList);
- PEdge -> Pnext = NULL;
- InsertEdgeToHashTbl1(PEdge);
- }
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to insert new edge to edge hash table structure sorted (hashed) by *
- * the edge Y min value. *
- * The edge is tested for duplicated entry (if interior edge it is entered *
- * twice from its two adjacent polygons). *
- * The edge is updated such that Ymin will be Vertex[0], Ymax Vertex[1]. *
- * *
- * PARAMETERS: *
- * PEdge: Edge to insert into hash table. *
- * *
- * RETURN VALUE: *
- * void *
- *****************************************************************************/
- static void InsertEdgeToHashTbl1(EdgeStruct *PEdge)
- {
- int Level;
- RealType Xmin, Xmax, Ymin, Ymax;
- IPVertexStruct *PVertex;
- EdgeStruct *PEtemp;
-
- if (PEdge -> Vertex[0] -> Coord[1] > PEdge -> Vertex[1] -> Coord[1]) {
- PVertex = PEdge -> Vertex[0];
- PEdge -> Vertex[0] = PEdge -> Vertex[1];
- PEdge -> Vertex[1] = PVertex;
- }
- Xmin = MIN(PEdge -> Vertex[0] -> Coord[0],
- PEdge -> Vertex[1] -> Coord[0]);
- Xmax = MAX(PEdge -> Vertex[0] -> Coord[0],
- PEdge -> Vertex[1] -> Coord[0]);
- Ymin = PEdge -> Vertex[0] -> Coord[1];
- Ymax = PEdge -> Vertex[1] -> Coord[1];
-
- if (GlblClipScreen && ((Ymin > 1.0) || (Ymax < -1.0) ||
- (Xmin > 1.0) || (Xmax < -1.0)))
- IritFree((VoidPtr) PEdge); /* Out of screen. */
- else {
- /* Normalize [-1..1] to [0..EDGE_HASH_TABLE_SIZE]: */
- Level = (int) ((Ymin + 1.0) * EDGE_HASH_TABLE_SIZE2);
- Level = BOUND(Level, 0, EDGE_HASH_TABLE_SIZE1); /* To be 100% safe. */
-
- /* Look for duplicate entry - it must have the same two vertices: */
- PEtemp = EdgeHashTable[Level];
- while (PEtemp) {
- /* Test to see if same edge by comparing vertices pointers. */
- if ((SAME_VERTEX(PEdge -> Vertex[0], PEtemp -> Vertex[0]) &&
- SAME_VERTEX(PEdge -> Vertex[1], PEtemp -> Vertex[1])) ||
- (SAME_VERTEX(PEdge -> Vertex[0], PEtemp -> Vertex[1]) &&
- SAME_VERTEX(PEdge -> Vertex[1], PEtemp -> Vertex[0]))) {
- IritFree((VoidPtr) PEdge);
- return; /* Ignore new entry! */
- }
- PEtemp = PEtemp -> Pnext;
- }
-
- if (!GlblQuiet)
- fprintf(stderr, "\b\b\b\b\b%5d", ++EdgeCount);
- PEdge -> Pnext = EdgeHashTable[Level]; /* Concat to main list. */
- EdgeHashTable[Level] = PEdge;
- }
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to collect all edges in hash table into one big list and intersect *
- * them beween themselves. *
- * The resulting edges are inserted back into the hash table. *
- * *
- * PARAMETERS: *
- * None *
- * *
- * RETURN VALUE: *
- * void *
- *****************************************************************************/
- static void IntersectAllEdges(void)
- {
- RealType Ymin;
- int i, Level;
- EdgeStruct *PEtemp,
- *PEmain = NULL;
-
- IritCPUTime(TRUE);
-
- EdgeCount = 0;
- MinYLevel = EDGE_HASH_TABLE_SIZE; /* Set "clip" levels in table entries. */
- MaxYLevel = 0;
-
- /* Clear the hash table and collect all edges into one big list: */
- for (i = EDGE_HASH_TABLE_SIZE1; i >= 0; i--)
- if ((PEtemp = EdgeHashTable[i]) != NULL) {
- while (PEtemp -> Pnext) PEtemp = PEtemp -> Pnext;
- PEtemp -> Pnext = PEmain;
- PEmain = EdgeHashTable[i];
- EdgeHashTable[i] = NULL;
- if (i > MaxYLevel)
- MaxYLevel = i;
- if (i < MinYLevel)
- MinYLevel = i;
- }
-
- PrintYLevel = CrntYLevel = 0; /* Have to start from some place... */
- if (!GlblQuiet)
- fprintf(stderr, "\nPass 3, Level [%5d] = ", MaxYLevel);
-
- while (PEmain) { /* Insert back after intersecting with all other edges. */
- PEtemp = PEmain -> Pnext; /* As PEmain->Pnext might be changed. */
- InsertEdgeToHashTbl2(PEmain);
- PEmain = PEtemp;
-
- /* Now test to see if we can update current y level: */
- if (CrntYLevel < MaxYLevel) {
- Ymin = MIN(PEmain -> Vertex[0] -> Coord[1],
- PEmain -> Vertex[1] -> Coord[1]);
- /* Normalize [-1..1] to [0..EDGE_HASH_TABLE_SIZE]: */
- Level = (int) ((Ymin + 1.0) * EDGE_HASH_TABLE_SIZE2);
- Level = BOUND(Level, 0, EDGE_HASH_TABLE_SIZE1); /* Be 100% safe. */
- if (Level > CrntYLevel)
- CrntYLevel = Level;
- }
- }
- if (!GlblQuiet)
- fprintf(stderr, ", %6.2f seconds.", IritCPUTime(FALSE));
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to insert old edge to edge hash table structure sorted (hashed) by *
- * the edge Y min value. The edge is tested for intersections with other *
- * edges allready in structure and both edges are broken if found one. *
- * *
- * PARAMETERS: *
- * PEdge: To back insert after intersection testing. *
- * *
- * RETURN VALUE: *
- * void *
- *****************************************************************************/
- static void InsertEdgeToHashTbl2(EdgeStruct *PEdge)
- {
- int i, Level, UpperLevel,
- FoundIntersection = FALSE;
- RealType Ymin, Ymax;
- EdgeStruct *PEtemp;
-
- Ymin = PEdge -> Vertex[0] -> Coord[1];
- Ymax = PEdge -> Vertex[1] -> Coord[1];
-
- /* Normalize [-1..1] to [0..EDGE_HASH_TABLE_SIZE]: */
- Level = (int) ((Ymin + 1.0) * EDGE_HASH_TABLE_SIZE2);
- Level = BOUND(Level, 0, EDGE_HASH_TABLE_SIZE1); /* To be 100% safe. */
- UpperLevel = 1 + (int) ((Ymax + 1.0) * EDGE_HASH_TABLE_SIZE2);
- UpperLevel = BOUND(UpperLevel, 0, EDGE_HASH_TABLE_SIZE1);
-
- if (CrntYLevel > PrintYLevel) {
- PrintYLevel = CrntYLevel;
- if (!GlblQuiet)
- fprintf(stderr, "\b\b\b\b\b%5d", PrintYLevel);
- }
-
- /* Test for intersections while we find intersections... */
- for (i=MinYLevel; i<=UpperLevel; i++)
- if (EdgeHashTable[i])
- if ((FoundIntersection =
- IntersectEdgeList(PEdge, EdgeHashTable[i],
- i == MinYLevel)) != 0)
- break;
-
- if (FoundIntersection) { /* Call recursively with the edge pieces: */
- while (PEdge) {
- PEtemp = PEdge -> Pnext; /* As Pedge->Pnext might point to new. */
- InsertEdgeToHashTbl2(PEdge); /* Place after the recursive ins. */
- PEdge = PEtemp;
- }
- }
- else { /* Its a single edge - insert it in its place: */
- EdgeCount++;
- PEdge -> Pnext = EdgeHashTable[Level]; /* Concat to main list. */
- EdgeHashTable[Level] = PEdge;
- }
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to scan all edges in list and intersect everything against *
- * the given edge. Intersected edges are broken into two. *
- * The broken edge is updated into a list of teo edges. *
- * This routine returns TRUE after the first intersection found, no test is *
- * made for ALL intersections if more than one exists. *
- * A test is made if MinYLevel can be updated if TestYMin == TRUE. *
- * *
- * PARAMETERS: *
- * PEdge: Edge to examine for intersection. *
- * PEList: List of edges to examine for intersectiong with PEdge. *
- * TestYMin: Index Y level. *
- * *
- * RETURN VALUE: *
- * int: TRUE if found intersection, FALSE otherwise. *
- *****************************************************************************/
- static int IntersectEdgeList(EdgeStruct *PEdge,
- EdgeStruct *PEList,
- int TestYMin)
- {
- int Level,
- UpdateYMin = TRUE;
- RealType Ymin, Ymax;
- EdgeStruct *PEdgeNew, *PEListNew;
-
- if (!PEdge || !PEList)
- return FALSE; /* NULL entry - quit. */
-
- while (PEList) {
- if (IntersectEdgeEdge(PEdge, PEList, &PEdgeNew, &PEListNew)) {
- PEdge -> Pnext = PEdgeNew;
- /* PEListNew can be inserted to the hash table with no check as */
- /* it cannot intersect anything - it is part of checked edge! */
- if (PEListNew) {
- Ymin = PEListNew -> Vertex[0] -> Coord[1];
- /* Normalize [-1..1] to [0..EDGE_HASH_TABLE_SIZE]: */
- Level = (int) ((Ymin + 1.0) * EDGE_HASH_TABLE_SIZE2);
- Level = BOUND(Level, 0, EDGE_HASH_TABLE_SIZE1);
- EdgeCount++;
- PEListNew -> Pnext = EdgeHashTable[Level];
- EdgeHashTable[Level] = PEListNew;
- }
- return TRUE;
- }
- if (TestYMin && UpdateYMin) {
- Ymax = PEList -> Vertex[1] -> Coord[1];
- /* Normalize [-1..1] to [0..EDGE_HASH_TABLE_SIZE]: */
- Level = (int) ((Ymax + 1.0) * EDGE_HASH_TABLE_SIZE2);
- Level = BOUND(Level, 0, EDGE_HASH_TABLE_SIZE1);
- if (Level >= CrntYLevel)
- UpdateYMin = FALSE;
- }
- PEList = PEList -> Pnext;
- }
- if (TestYMin && UpdateYMin) /* No need to test any more. */
- do
- MinYLevel++;
- while (MinYLevel < CrntYLevel && !EdgeHashTable[MinYLevel]);
-
- return FALSE;
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to test if two edges intersects. If they do, it brakes the bottom *
- * edge into two pieces, leaving the lower part (with the same Ymin) in *
- * original struct and allocates and updates new struct with upper edge part. *
- * Returns TRUE if found intersection, FALSE otherwise. *
- * The intersection is tested in the XY axes (Z is ignored). *
- * *
- * *
- * PARAMETERS: *
- * PEdge1, PEdge2: Two edge to intersect against each other. *
- * PEdgeNew1: If PEdge1 is broken into two. *
- * PEdgeNew2: If PEdge2 is broken into two. *
- * *
- * RETURN VALUE: *
- * int: TRUE if found intersection, FALSE otherwise. *
- *****************************************************************************/
- static int IntersectEdgeEdge(EdgeStruct *PEdge1,
- EdgeStruct *PEdge2,
- EdgeStruct **PEdgeNew1,
- EdgeStruct **PEdgeNew2)
- {
- int i, OneInter1, OneInter2;
- RealType Xmin1, Xmax1, Ymin1, Ymax1, Xmin2, Xmax2, Ymin2, Ymax2,
- a1, b11, b12, a2, b21, b22, det, t1, t2, Z1, Z2;
- /* To speed up the intensive access of the coordinates: */
- RealType
- *Crd10 = PEdge1 -> Vertex[0] -> Coord,
- *Crd11 = PEdge1 -> Vertex[1] -> Coord,
- *Crd20 = PEdge2 -> Vertex[0] -> Coord,
- *Crd21 = PEdge2 -> Vertex[1] -> Coord;
-
- Xmin1 = MIN(Crd10[0], Crd11[0]);
- Xmax1 = MAX(Crd10[0], Crd11[0]);
- Ymin1 = Crd10[1];
- Ymax1 = Crd11[1];
-
- Xmin2 = MIN(Crd20[0], Crd21[0]);
- Xmax2 = MAX(Crd20[0], Crd21[0]);
- Ymin2 = Crd20[1];
- Ymax2 = Crd21[1];
- if ((Xmin1 > Xmax2) || (Xmax1 < Xmin2) ||/* Test if out of Boundary Box. */
- (Ymin1 > Ymax2) || (Ymax1 < Ymin2))
- return FALSE;
-
- /* Let the line equations of the two edges be defined as: */
- /* L1 = p11 + t1 * (pt12 - pt11) , t1 = [0..1] */
- /* L2 = p21 + t2 * (pt22 - pt21) , t2 = [0..1] */
- /* at intersection point (if any) we have: */
- /* pt11 + t1 * (pt12 - pt11) == pt21 + t2 * (pt22 - pt21) for x, y */
- /* or two equations (for x, y) with two unknown (t1, t2) to solve: */
- /* a1 = b11 * t1 + b12 * t2 from x */
- /* a2 = b21 * t1 + b22 * t2 from y */
- /* and we have interesection if both t1, t2 in the range [0..1] */
- a1 = Crd10[0] - Crd20[0];
- b11 = Crd10[0] - Crd11[0];
- b12 = Crd21[0] - Crd20[0];
- a2 = Crd10[1] - Crd20[1];
- b21 = Crd10[1] - Crd11[1];
- b22 = Crd21[1] - Crd20[1];
-
- /* If the detereminant is zero, the two lines are parellel - no inter. */
- if (APX_EQ((det = b11 * b22 - b21 * b12), 0.0))
- return FALSE;
-
- t1 = (a1 * b22 - a2 * b12) / det;
- t2 = (b11 * a2 - b21 * a1) / det;
-
- /* Test if intersection is happening in one edge END - in that case */
- /* we break only the second edge into two parts. */
- OneInter1 = ((t1 < 1.0) && (t1 > 0.0) &&
- !(APX_EQ(t1, 0.0) || APX_EQ(t1, 1.0)) &&
- (APX_EQ(t2, 0.0) || APX_EQ(t2, 1.0)));
- OneInter2 = ((t2 < 1.0) && (t2 > 0.0) &&
- !(APX_EQ(t2, 0.0) || APX_EQ(t2, 1.0)) &&
- (APX_EQ(t1, 0.0) || APX_EQ(t1, 1.0)));
-
- /* If out of 0..1 range in one of edges - no intersection: */
- if ((!(OneInter1 || OneInter2)) &&
- ((t1 >= 1.0) || (t1 <= 0.0) || (t2 >= 1.0) || (t2 <= 0.0) ||
- APX_EQ(t1, 0.0) || APX_EQ(t1, 1.0) ||
- APX_EQ(t2, 0.0) || APX_EQ(t2, 1.0))) return FALSE;
-
- /* If we are here, we have intersection - find the bottom edge and split */
- /* it - allocated new edge struct and update to new upper (in Y) part. */
- Z1 = Crd10[2] * (1.0 - t1) + Crd11[2] * t1;
- Z2 = Crd20[2] * (1.0 - t2) + Crd21[2] * t2;
- if (!OneInter2 && Z1 < Z2) {
- *PEdgeNew1 = (EdgeStruct *) IritMalloc(sizeof(EdgeStruct));
- (*PEdgeNew1) -> Pnext = NULL;
- (*PEdgeNew1) -> Internal = PEdge1 -> Internal;
- (*PEdgeNew1) -> Vertex[0] = IPAllocVertex(0, 0, NULL, NULL);
- for (i = 0; i < 2; i++)
- (*PEdgeNew1) -> Vertex[0] -> Coord[i] =
- Crd10[i] * (1.0 - t1) + Crd11[i] * t1;
- (*PEdgeNew1) -> Vertex[0] -> Coord[2] = Z1;
- /* Now update the second vertex of both PEdge1 & PEdgeNew1: */
- /* Note we assume Vertex[0] -> Coord[1] < Vertex[1] -> Coord[1] as */
- /* all input edges are sorted this way when entered to hash table. */
- (*PEdgeNew1) -> Vertex[1] = PEdge1 -> Vertex[1];
- PEdge1 -> Vertex[1] = (*PEdgeNew1) -> Vertex[0];
-
- }
- else
- *PEdgeNew1 = NULL;
-
- if (!OneInter1 && Z2 < Z1) {
- *PEdgeNew2 = (EdgeStruct *) IritMalloc(sizeof(EdgeStruct));
- (*PEdgeNew2) -> Pnext = NULL;
- (*PEdgeNew2) -> Internal = PEdge2 -> Internal;
- (*PEdgeNew2) -> Vertex[0] = IPAllocVertex(0, 0, NULL, NULL);
- for (i = 0; i < 2; i++)
- (*PEdgeNew2) -> Vertex[0] -> Coord[i] =
- Crd20[i] * (1.0 - t2) + Crd21[i] * t2;
- (*PEdgeNew2) -> Vertex[0] -> Coord[2] = Z2;
- /* Now update the second vertex of both PEdge2 & PEdgeNew2: */
- (*PEdgeNew2) -> Vertex[1] = PEdge2 -> Vertex[1];
- PEdge2 -> Vertex[1] = (*PEdgeNew2) -> Vertex[0];
- }
- else
- *PEdgeNew2 = NULL;
-
- return (*PEdgeNew1 != NULL) || (*PEdgeNew2 != NULL);
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to print the content of a given edge: *
- * *
- * PARAMETERS: *
- * PPoly: To print content of. *
- * *
- * RETURN VALUE: *
- * void *
- *****************************************************************************/
- static void PrintPolyContent(IPPolygonStruct *PPoly)
- {
- IPVertexStruct
- *PList = PPoly -> PVertex;
-
- while (PList) {
- fprintf(stderr, " %12f %12f %12f\n",
- PList -> Coord[0],
- PList -> Coord[1],
- PList -> Coord[2]);
- PList = PList -> Pnext;
- }
- }
-
- #ifdef DEBUG1
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to print the content of a given edge: *
- * *
- * PARAMETERS: *
- * PEdge: To print content of *
- * *
- * RETURN VALUE: *
- * void *
- *****************************************************************************/
- static void PrintEdgeContent(EdgeStruct *PEdge)
- {
- fprintf(stderr, " %11f %11f %11f : %11f %11f %11f\n",
- PEdge -> Vertex[0] -> Coord[0],
- PEdge -> Vertex[0] -> Coord[1],
- PEdge -> Vertex[0] -> Coord[2],
- PEdge -> Vertex[1] -> Coord[0],
- PEdge -> Vertex[1] -> Coord[1],
- PEdge -> Vertex[1] -> Coord[2]);
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to dump all the segments in the EdgeHashTable as IRIT data file so *
- * it can be displayed, to stdout. *
- * *
- * PARAMETERS: *
- * None *
- * *
- * RETURN VALUE: *
- * void *
- *****************************************************************************/
- static void DrawEdgeHashTable(void)
- {
- int i;
- EdgeStruct *PEtemp;
-
- for (i=0; i<EDGE_HASH_TABLE_SIZE; i++) {
- PEtemp = EdgeHashTable[i];
- while(PEtemp) {
- DrawEdge(PEtemp);
- PEtemp = PEtemp -> Pnext;
- }
- }
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to dump one segment as IRIT data file so it can be displayed, to *
- * stdout. *
- * *
- * PARAMETERS: *
- * None *
- * *
- * RETURN VALUE: *
- * void *
- *****************************************************************************/
- static void DrawEdge(EdgeStruct *PEdge)
- {
- printf(" [POINTLIST 2\n\t[%lf %lf %lf]\n\t[%lf %lf %lf]\n ]\n",
- PEdge->Vertex[0]->Coord[0],
- PEdge->Vertex[0]->Coord[1],
- PEdge->Vertex[0]->Coord[2],
- PEdge->Vertex[1]->Coord[0],
- PEdge->Vertex[1]->Coord[1],
- PEdge->Vertex[1]->Coord[2]);
- printf(" [POLYLINE 2\n\t[%lf %lf %lf]\n\t[%lf %lf %lf]\n ]\n",
- PEdge->Vertex[0]->Coord[0],
- PEdge->Vertex[0]->Coord[1],
- PEdge->Vertex[0]->Coord[2],
- PEdge->Vertex[1]->Coord[0],
- PEdge->Vertex[1]->Coord[1],
- PEdge->Vertex[1]->Coord[2]);
- }
-
- #endif /* DEBUG1 */
-